package com.ml.framework.tools;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;

public class BeanUtils // extends org.springframework.beans.BeanUtils
{
	static
	{
		ConvertUtils.register(new DateConverter(), java.util.Date.class);
		ConvertUtils.register(new DateConverter(), java.lang.String.class);
	}

	public static void copyAnyProps(Object orig, Object dest, String ignoreProperties[], boolean ignoreNull) throws Exception
	{
		copyAnyProps(orig, dest, ignoreProperties, false, ignoreNull);
	}

	/**
	 * 复制对象的属性
	 * 
	
	 * @param orig 原对象
	 * @param dest 目标对象
	 * @param ignoreProperties 不处理的属性
	 * @param reverse 这个变量控制刚好相反，即只处理ignoreProperties指定的属性
	 * @param ignoreNull 忽略属性值为null的复制 true 表示为空时不复制，false 复制
	 * @throws Exception
	 */
	public static void copyAnyProps(Object orig, Object dest, String ignoreProperties[], boolean reverse, boolean ignoreNull) throws Exception
	{
		if (dest == null)
			throw new IllegalArgumentException("No destination bean specified");
		if (orig == null)
			throw new IllegalArgumentException("No origin bean specified");

		List<?> ignoreList = ignoreProperties == null ? null : Arrays.asList(ignoreProperties);
		BeanUtilsBean beanUtils = BeanUtilsBean.getInstance();
		PropertyUtilsBean propUtil = beanUtils.getPropertyUtils();

		if (orig instanceof DynaBean)
		{
			DynaProperty origDescriptors[] = ((DynaBean) orig).getDynaClass().getDynaProperties();
			for (int i = 0; i < origDescriptors.length; i++)
			{
				String name = origDescriptors[i].getName();
				if (reverse)
				{
					if (ignoreList != null && !ignoreList.contains(name))
						continue;
				}
				else
				{
					if (ignoreList != null && ignoreList.contains(name))
						continue;
				}
				if (propUtil.isReadable(orig, name) && propUtil.isWriteable(dest, name))
				{
					Object value = ((DynaBean) orig).get(name);
					if (ignoreNull && value == null)
						continue;
					if (value == null)
						propUtil.setProperty(dest, name, value);
					else
						beanUtils.copyProperty(dest, name, value);
				}
			}
		}
		else if (orig instanceof Map)
		{
			Iterator<?> entries = ((Map<?, ?>) orig).entrySet().iterator();
			do
			{
				if (!entries.hasNext())
					break;
				java.util.Map.Entry<?, ?> entry = (java.util.Map.Entry<?, ?>) entries.next();
				String name = (String) entry.getKey();

				if (reverse)
				{
					if (ignoreList != null && !ignoreList.contains(name))
						continue;
				}
				else
				{
					if (ignoreList != null && ignoreList.contains(name))
						continue;
				}

				Object value = entry.getValue();
				if (ignoreNull && value == null)
					continue;
				if (dest instanceof Map)
				{
					propUtil.setProperty(dest, name, value);
				}
				else if (propUtil.isWriteable(dest, name))
				{
					if (value == null)
						propUtil.setProperty(dest, name, value);
					else
						beanUtils.copyProperty(dest, name, value);
				}
			} while (true);
		}
		else
		{
			PropertyDescriptor origDescriptors[] = propUtil.getPropertyDescriptors(orig);
			for (int i = 0; i < origDescriptors.length; i++)
			{
				String name = origDescriptors[i].getName();
				if (reverse)
				{
					if (ignoreList != null && !ignoreList.contains(name))
						continue;
				}
				else
				{
					if (ignoreList != null && ignoreList.contains(name))
						continue;
				}
				if ("class".equals(name) || !propUtil.isReadable(orig, name) || !propUtil.isWriteable(dest, name))
					continue;
				try
				{
					Object value = propUtil.getSimpleProperty(orig, name);
					if (ignoreNull && value == null)
						continue;

					if (value == null)
						propUtil.setProperty(dest, name, value);
					else
						beanUtils.copyProperty(dest, name, value);
				}
				catch (NoSuchMethodException e)
				{
				}
			}
		}
	}

	/**
	 * 获取对象的属性的值
	 * 
	
	 * @param bean
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public static String getAnyProp(Object bean, String name) throws Exception
	{
		return BeanUtilsBean.getInstance().getProperty(bean, name);
	}

	/**
	 * 设置对象的属性的值
	 * 
	
	 * @param bean
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public static void setAnyProp(Object bean, String name, Object value) throws Exception
	{
		if (bean instanceof Map || value == null)
			BeanUtilsBean.getInstance().getPropertyUtils().setProperty(bean, name, value);
		else
			BeanUtilsBean.getInstance().copyProperty(bean, name, value);
	}

	/**
	 * 将对象系列化成MAP
	 * 
	
	 * @param bean
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Object> describe(Object bean) throws Exception
	{
		return describe(bean, false);
	}

	/**
	 * 将对象系列化成MAP
	 * 
	
	 * @param bean
	 * @param ignoreNull
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Object> describe(Object bean, boolean ignoreNull) throws Exception
	{
		if (bean == null)
			return new HashMap<String, Object>();

		BeanUtilsBean butils = BeanUtilsBean.getInstance();

		Map<String, Object> description = new HashMap<String, Object>();
		if (bean instanceof DynaBean)
		{
			DynaProperty descriptors[] = ((DynaBean) bean).getDynaClass().getDynaProperties();
			for (int i = 0; i < descriptors.length; i++)
			{
				String name = descriptors[i].getName();
				Object value = butils.getProperty(bean, name);
				if (!ignoreNull || value != null)
				{
					description.put(name, value);
				}
			}
		}
		else
		{
			PropertyDescriptor descriptors[] = butils.getPropertyUtils().getPropertyDescriptors(bean);
			Class<?> clazz = bean.getClass();
			for (int i = 0; i < descriptors.length; i++)
			{
				if (getReadMethod(clazz, descriptors[i]) != null)
				{
					String name = descriptors[i].getName();
					Object value = butils.getProperty(bean, name);
					if (!ignoreNull || value != null)
					{
						description.put(name, value);
					}
				}
			}

		}
		return description;
	}

	private static Method getReadMethod(Class<?> clazz, PropertyDescriptor descriptor)
	{
		return MethodUtils.getAccessibleMethod(clazz, descriptor.getReadMethod());
	}
}
